﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using NUnit.Framework;
using CID.Tests.Support;
using CID.Domain.Audit;

namespace CID.Domain.Persistence.Tests.Audit
{
    [TestFixture]
    class ReleaseDeploymentLogPersistenceTests : BasePersistenceWithDataTests
    {
        #region Asserts
        private static void AssertAreEqual(ReleaseDeploymentLog expected, ReleaseDeploymentLog actual)
        {
            Assert.AreEqual(expected.Id, actual.Id);
            Assert.AreEqual(expected.Environment.Id, actual.Environment.Id);
            Assert.AreEqual(expected.Responsible.Id, actual.Responsible.Id);
            Assert.AreEqual(expected.Release.Id, actual.Release.Id);
            Assert.AreEqual(expected.DeploymentUniqueIdentifier, actual.DeploymentUniqueIdentifier);
            Assert.AreEqual(expected.Details, actual.Details);
            AssertAreEqual(expected.StartTimestamp, actual.StartTimestamp);
            AssertAreEqual(expected.EndTimestamp, actual.EndTimestamp);
            Assert.AreEqual(expected.Status, actual.Status);
            var expectedVersions = expected.Versions.OfType<VersionDeploymentLog>().OrderBy(x => x.Id).ToArray();
            var actualVersions = actual.Versions.OfType<VersionDeploymentLog>().OrderBy(x => x.Id).ToArray();
            CollectionAssert.AreEqual(expectedVersions.Select(x => x.Id), actualVersions.Select(x => x.Id));
            for (int i = 0; i < expectedVersions.Length; i++)
                AssertAreEqual(expectedVersions[i], actualVersions[i]);
        }

        private static void AssertAreEqual(DateTime? expected, DateTime? actual)
        {
            Assert.AreEqual(expected.HasValue, actual.HasValue);
            if (expected.HasValue)
            {
                Assert.AreEqual(expected.Value.Year, actual.Value.Year);
                Assert.AreEqual(expected.Value.Month, actual.Value.Month);
                Assert.AreEqual(expected.Value.Day, actual.Value.Day);
                Assert.AreEqual(expected.Value.Hour, actual.Value.Hour);
                Assert.AreEqual(expected.Value.Minute, actual.Value.Minute);
                Assert.AreEqual(expected.Value.Second, actual.Value.Second);
            }
        }

        private static void AssertAreEqual(VersionDeploymentLog expected, VersionDeploymentLog actual)
        {
            Assert.AreEqual(expected.Id, actual.Id);
            Assert.AreEqual(expected.ActivationTemplate.Id, actual.ActivationTemplate.Id);
            Assert.AreEqual(expected.DeactivationTemplate.Id, actual.DeactivationTemplate.Id);
            Assert.AreEqual(expected.DeploymentTemplate.Id, actual.DeploymentTemplate.Id);
            Assert.AreEqual(expected.Version.Id, actual.Version.Id);
            Assert.AreEqual(expected.ReleaseDeploymentLog.Id, actual.ReleaseDeploymentLog.Id);
            var expectedParameters = expected.Parameters.OfType<ParameterDeploymentLog>().OrderBy(x => x.Id).ToArray();
            var actualParameters = actual.Parameters.OfType<ParameterDeploymentLog>().OrderBy(x => x.Id).ToArray();
            CollectionAssert.AreEqual(expectedParameters.Select(x => x.Id), actualParameters.Select(x => x.Id));
            for (int i = 0; i < expectedParameters.Length; i++)
                AssertAreEqual(expectedParameters[i], actualParameters[i]);
        }

        private static void AssertAreEqual(ParameterDeploymentLog expected, ParameterDeploymentLog actual)
        {
            Assert.AreEqual(expected.Id, actual.Id);
            Assert.AreEqual(expected.VersionDeploymentLog.Id, actual.VersionDeploymentLog.Id);
            Assert.AreEqual(expected.ParameterName, actual.ParameterName);
            Assert.AreEqual(expected.ParameterValue, actual.ParameterValue);
        }
        #endregion

        [Test]
        public void PersistNewReleaseDeploymentLog_ReleaseDeploymentLogShouldBeSaved()
        {
            var session = OpenSession();
            var newReleaseDeploymentLog = DataProvider.CreateReleaseDeploymentLog(session, DevelopmentData.Release1, OperationsData.Environment1, UsersData.User2);
            session.SaveOrUpdate(newReleaseDeploymentLog);
            CleanSession(session);

            Assert.AreNotEqual(NotSavedId, newReleaseDeploymentLog.Id);
            session = OpenSession();
            var retrievedReleaseDeploymentLog = session.Get<ReleaseDeploymentLog>(newReleaseDeploymentLog.Id);
            AssertAreEqual(newReleaseDeploymentLog, retrievedReleaseDeploymentLog);
            CleanSession(session);
        }

        [Test]
        public void PersistModifiedReleaseDeploymentLog_ChangesShouldBeSaved()
        {
            var session = OpenSession();
            var newReleaseDeploymentLog = DataProvider.CreateReleaseDeploymentLog(session, DevelopmentData.Release1, OperationsData.Environment1, UsersData.User2);
            session.SaveOrUpdate(newReleaseDeploymentLog);
            CleanSession(session);

            session = OpenSession();
            var modifiedReleaseDeploymentLog = session.Get<ReleaseDeploymentLog>(newReleaseDeploymentLog.Id);
            AssertAreEqual(newReleaseDeploymentLog, modifiedReleaseDeploymentLog); //Needed to force lazy collections to load before the session is wiped
            modifiedReleaseDeploymentLog.ModifyProperty(x => x.Details);
            modifiedReleaseDeploymentLog.Start();
            session.SaveOrUpdate(modifiedReleaseDeploymentLog);
            CleanSession(session);

            session = OpenSession();
            var retrievedReleaseDeploymentLog = session.Get<ReleaseDeploymentLog>(newReleaseDeploymentLog.Id);
            AssertAreEqual(modifiedReleaseDeploymentLog, retrievedReleaseDeploymentLog);
            CleanSession(session);
        }

        [Test]
        public void DeleteReleaseDeploymentLog_ReleaseDeploymentLogShouldBeDeleted()
        {
            var session = OpenSession();
            var newReleaseDeploymentLog1 = DataProvider.CreateReleaseDeploymentLog(session, DevelopmentData.Release1, OperationsData.Environment1, UsersData.User2);
            var newReleaseDeploymentLog2 = DataProvider.CreateReleaseDeploymentLog(session, DevelopmentData.Release2, OperationsData.Environment1, UsersData.User2);
            session.SaveOrUpdate(newReleaseDeploymentLog1);
            session.SaveOrUpdate(newReleaseDeploymentLog2);
            CleanSession(session);

            session = OpenSession();
            var retrievedReleaseDeploymentLog1 = session.Get<ReleaseDeploymentLog>(newReleaseDeploymentLog1.Id);
            session.Delete(retrievedReleaseDeploymentLog1);
            CleanSession(session);

            session = OpenSession();
            retrievedReleaseDeploymentLog1 = session.Get<ReleaseDeploymentLog>(newReleaseDeploymentLog1.Id);
            var retrievedReleaseDeploymentLog2 = session.Get<ReleaseDeploymentLog>(newReleaseDeploymentLog2.Id);
            Assert.IsNull(retrievedReleaseDeploymentLog1);
            Assert.IsNotNull(retrievedReleaseDeploymentLog2);
            CleanSession(session);
        }
    }
}
